<template>
  <!-- 
    传感器数据主容器 - 定义页面整体布局和背景
    使用flex布局实现响应式设计，min-height确保内容区域最小高度为视口高度
    padding使用rpx单位实现不同屏幕尺寸的自适应
  -->
  <view class="sensor-container">
    <!-- 
      顶部工具栏 - 包含搜索和功能图标
      使用flex布局实现元素水平排列，space-between实现两端对齐
      @touchstart等事件可通过uni-app手势系统扩展交互
    -->
    <view class="toolbar">
      <!-- 
        搜索输入框 - 支持用户输入查询条件
        placeholder属性提供输入提示，v-model可双向绑定搜索值(需添加)
        border-radius实现圆角效果，padding增加点击区域
      -->
      <input class="search-input" placeholder="请输入属性名称或标识符" />
      <!-- 
        工具图标组 - 提供辅助功能入口
        gap属性控制图标间距，size统一图标尺寸
        实际项目应添加@click事件处理
      -->
      <view class="tool-icons">
        <uni-icons type="grid" size="24" />
        <uni-icons type="more" size="24" />
        <uni-icons type="help" size="24" />
      </view>
    </view>

    <!-- 
      数据卡片组 - 使用CSS Grid布局实现响应式卡片排列
      auto-fit和minmax()实现自适应列宽，gap控制卡片间距
      实际项目可添加v-for动态渲染卡片
    -->
    <view class="card-group">
      <!-- 
        温度数据卡片 - 每张卡片独立组件更佳
        normal类名可用于状态指示(如warning/error状态)
        @click添加事件委托可优化性能
      -->
      <view class="data-card normal">
        <view class="card-header">
          <!-- 
            图标使用uni-app内置图标组件
            颜色使用主题色，实际项目可从配置读取
          -->
          <uni-icons type="thermometer" size="28" color="#2196F3" />
          <text class="card-title">温度</text>
          <!-- 
            查看选项 - 实际项目应使用组件拆分
            @click应阻止事件冒泡避免冲突
          -->
          <text class="view-options" @click="showDetail('temperature')">查看数据 | 查看日志</text>
        </view>
        <view class="card-body">
          <!-- 
            数据值显示 - 使用计算属性确保格式统一
            空值处理逻辑在computed中实现
          -->
          <text class="data-value">{{ formatTemperature }}℃</text>
          <!-- 
            时间戳 - 使用统一格式化方法
            每秒更新通过定时器实现
          -->
          <text class="timestamp">{{ lastUpdate }}</text>
        </view>
      </view>

      <!-- 湿度卡片 - 结构类似温度卡片 -->
      <view class="data-card normal">
        <view class="card-header">
          <uni-icons type="humidity" size="28" color="#4CAF50" />
          <text class="card-title">湿度</text>
          <text class="view-options" @click="showDetail('Humidity')">查看数据 | 查看日志</text>
        </view>
        <view class="card-body">
          <text class="data-value">{{ formatHumidity }}%RH</text>
          <text class="timestamp">{{ lastUpdate }}</text>
        </view>
      </view>

      <!-- 光照卡片 - 直接显示原始值 -->
      <view class="data-card normal">
        <view class="card-header">
          <uni-icons type="sun" size="28" color="#FF9800" />
          <text class="card-title">光照强度</text>
          <text class="view-options" @click="showDetail('LightLux')">查看数据 | 查看日志</text>
        </view>
        <view class="card-body">
          <!-- 零值处理避免显示undefined/null -->
          <text class="data-value">{{ sensorData.LightLux || 0 }}Lux</text>
          <text class="timestamp">{{ lastUpdate }}</text>
        </view>
      </view>

      <!-- 土壤湿度卡片 - 特殊格式显示 -->
      <view class="data-card normal">
        <view class="card-header">
          <uni-icons type="soil" size="28" color="#9C27B0" />
          <text class="card-title">土壤湿度</text>
          <text class="view-options" @click="showDetail('soilHumidity')">查看数据 | 查看日志</text>
        </view>
        <view class="card-body">
          <!-- 计算属性实现数值转换和格式化 -->
          <text class="data-value">{{ soilHumidityData }}</text>
          <text class="timestamp">{{ lastUpdate }}</text>
        </view>
      </view>
    </view>

    <!-- 
      状态栏 - 显示系统信息和错误
      v-if控制错误信息显示，避免空内容占位
    -->
    <view class="status-bar">
      <text>数据每分钟自动更新 | 当前版本: 1.2.4</text>
      <!-- 错误信息使用醒目颜色，margin-top增加垂直间距 -->
      <text v-if="errorMessage" style="color:red;margin-top:10rpx">{{ errorMessage }}</text>
    </view>
    
    <!-- 
      加载指示器 - 使用固定定位覆盖全屏
      z-index确保在最上层，rgba背景实现半透效果
    -->
    <view v-if="loading" class="loading-overlay">
      <view class="loading-spinner">
        <!-- 使用旋转动画图标增强等待体验 -->
        <uni-icons type="spinner-cycle" size="36" color="#2196F3" />
        <text class="loading-text">数据加载中...</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  // Vue 组件数据模型 - 定义组件内部状态
  data() {
    return {
      // 传感器数据结构 - 初始值避免undefined错误
      sensorData: {
        LightLux: 0,     // 光照强度
        Humidity: 0,      // 环境湿度
        soilHumidity: 0,  // 土壤湿度
        temperature: 0    // 温度值
      },
      // 最后更新时间 - 初始显示加载状态
      lastUpdate: '加载中...',
      // 定时器引用 - 便于组件销毁时清理
      updateTimer: null,   // 时间更新定时器
      dataTimer: null,     // 数据获取定时器
      // 错误处理 - 用户可见的错误信息
      errorMessage: '',
      // 调试信息 - 存储请求/响应详细信息
      debugInfo: {},
      // 加载状态 - 控制加载动画显示
      loading: true,
      // 重试机制 - 限制失败请求次数
      retryCount: 0
    };
  },
  
  /*
    计算属性 - 基于依赖的缓存机制
    1. 自动追踪依赖，仅相关变化时重新计算
    2. 避免在模板中编写复杂逻辑
    3. 保持模板简洁易读
  */
  computed: {
    // 温度格式化 - 保留小数/空值处理
    formatTemperature() {
      const temp = this.sensorData.temperature;
      // 使用三元表达式处理边界情况
      return temp !== undefined && temp !== null ? temp.toFixed(1) : '--';
    },
    // 湿度格式化 - 逻辑同温度
    formatHumidity() {
      const humid = this.sensorData.Humidity;
      return humid !== undefined && humid !== null ? humid.toFixed(1) : '--';
    },
    // 土壤湿度特殊格式化 - 原始值+百分比
    soilHumidityData() {
      const soil = this.sensorData.soilHumidity;
      // 双重验证确保数据安全
      if (soil === undefined || soil === null) return '--';
      
      // 数值转换 (0-4095 → 0-100%)
      const percentage = ((soil / 4095) * 100).toFixed(1);
      return `${soil} (${percentage}%)`;
    }
  },
  
  /*
    方法集合 - 组件业务逻辑
    1. 使用ES6语法简化代码
    2. 功能拆分为独立方法
    3. 添加JSDoc增强可维护性
  */
  methods: {
    /**
     * 时间格式化方法
     * @param {number} timestamp - 毫秒时间戳
     * @returns {string} 格式化时间字符串 (YYYY/MM/DD HH:mm:ss)
     */
    formatTime(timestamp) {
      const date = new Date(timestamp);
      // 辅助函数补零
      const pad = n => n.toString().padStart(2, '0');
      // 拼接各时间部分
      return `${date.getFullYear()}/${pad(date.getMonth()+1)}/${pad(date.getDate())} ` +
             `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
    },
    
    /**
     * 显示详情 - 预留功能入口
     * @param {string} prop - 属性标识符
     */
    showDetail(prop) {
      // 实际项目应使用路由跳转
      console.log(`查看${prop}详情`);
      // uni.navigateTo({ url: `/pages/detail?prop=${prop}` })
    },

    /**
     * 获取传感器数据 - 核心数据获取方法
     * 1. 异步请求避免阻塞UI
     * 2. 错误处理机制完备
     * 3. 重试策略提升用户体验
     */
    async fetchData() {
      try {
        // 进入加载状态
        this.loading = true;
        this.errorMessage = '';
        
        // 调用uniCloud云函数
        const res = await uniCloud.callFunction({
          name: 'getSensorData',
          timeout: 20000 // 20秒超时
        });
        
        // 调试信息记录
        console.log('云函数响应:', res);
        this.debugInfo = {
          requestTime: new Date().toLocaleString(),
          responseData: res.result
        };
        
        // 处理权限错误 (403)
        if (res.result?.code === 403) {
          this.showPermissionError(res.result.error);
          return;
        }
        
        // 成功状态处理 (200/206)
        if ([200, 206].includes(res.result?.code)) {
          // 使用对象展开符合并数据
          this.sensorData = {
            ...this.sensorData,
            ...res.result.data
          };
          
          // 时间戳处理 (优先使用服务器时间)
          const serverTime = Object.values(res.result.timestamps)[0];
          this.lastUpdate = serverTime ? 
            this.formatTime(serverTime) : 
            this.formatTime(Date.now());
          
          // 重置重试计数器
          this.retryCount = 0;
        } 
        // 无数据状态处理 (503)
        else if (res.result?.code === 503) {
          console.warn('无有效数据，使用默认值');
          this.sensorData = {
            LightLux: 0,
            Humidity: 0,
            soilHumidity: 0,
            temperature: 0
          };
          this.lastUpdate = this.formatTime(Date.now());
        } 
        // 其他错误处理
        else {
          this.handleError(res.result);
        }
      } catch (err) {
        console.error('调用云函数失败:', err);
        
        // 指数退避重试策略
        if (this.retryCount < 3) {
          this.retryCount++;
          const delay = Math.pow(2, this.retryCount) * 1000;
          console.log(`第${this.retryCount}次重试，${delay}ms后执行...`);
          setTimeout(() => this.fetchData(), delay);
          return;
        }
        
        // 重试失败处理
        this.errorMessage = '获取数据失败，请检查网络连接';
        uni.showToast({
          title: '获取数据失败',
          icon: 'none'
        });
      } finally {
        // 无论成功失败都解除加载状态
        this.loading = false;
      }
    },
    
    /**
     * 权限错误处理 - 模态框提示用户
     * @param {string} error - 错误详情
     */
    showPermissionError(error) {
      uni.showModal({
        title: '权限配置错误',
        content: error,
        showCancel: false,
        confirmText: '我知道了'
      });
      this.errorMessage = '权限配置异常';
    },
    
    /**
     * 通用错误处理 - 多种错误格式支持
     * @param {Object} result - 错误响应对象
     */
    handleError(result) {
      // 错误信息提取策略
      const errorMsg = 
        result?.errors ? Object.values(result.errors)[0] :
        result?.error ? result.error :
        result?.message ? result.message : 
        '未知错误';
      
      this.errorMessage = errorMsg;
      uni.showToast({
        title: errorMsg,
        icon: 'none',
        duration: 3000
      });
    },
    
    /**
     * 定时器初始化 - 组件数据更新机制
     * 1. 数据获取定时器 (60秒间隔)
     * 2. 时间显示更新定时器 (1秒间隔)
     */
    initTimers() {
      // 初始数据获取
      this.fetchData();

      // 数据轮询 (60秒)
      this.dataTimer = setInterval(() => {
        this.fetchData();
      }, 60000);
      
      // 时钟更新 (1秒)
      this.updateTimer = setInterval(() => {
        this.lastUpdate = this.formatTime(Date.now());
      }, 1000);
    }
  },
  
  /*
    Vue生命周期钩子 - 组件状态管理
    1. mounted: 组件挂载后初始化
    2. beforeDestroy: 组件销毁前清理
  */
  mounted() {
    // 初始化定时器
    this.initTimers();
  },
  
  beforeDestroy() {
    // 清理定时器防止内存泄漏
    clearInterval(this.dataTimer);
    clearInterval(this.updateTimer);
  }
};
</script>

<style lang="scss">
/* 使用SCSS增强样式能力 */
/* 响应式容器 - 使用rpx单位 */
.sensor-container {
  padding: 20rpx;
  background: #f8f9fa; 
  position: relative;
  min-height: 100vh; /* 最小高度保证布局完整 */
}

/* 工具栏 - Flex布局实现灵活排列 */
.toolbar {
  display: flex;
  justify-content: space-between; /* 两端对齐 */
  margin-bottom: 20rpx;
  padding: 0 20rpx;

  .search-input {
    width: 60%;
    padding: 12rpx;
    border: 1rpx solid #ddd;
    border-radius: 24rpx; /* 圆角输入框 */
    font-size: 28rpx;
  }

  .tool-icons {
    display: flex;
    gap: 20rpx; /* CSS Gap属性控制间距 */
    align-items: center;
  }
}

/* 卡片组 - CSS Grid布局 */
.card-group {
  display: grid;
  /* 响应式列：最小340rpx，自动填充 */
  grid-template-columns: repeat(auto-fit, minmax(340rpx, 1fr));
  gap: 20rpx;
  padding: 0 20rpx;
}

/* 数据卡片 - 阴影增强层次感 */
.data-card {
  background: white;
  border-radius: 16rpx;
  padding: 24rpx;
  box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.08); /* 微妙阴影 */
  
  .card-header {
    display: flex;
    align-items: center;
    margin-bottom: 16rpx;
    
    .uni-icons {
      margin-right: 12rpx;
    }
    
    .card-title {
      font-size: 30rpx;
      font-weight: 600;
      color: #333;
      flex-grow: 1; /* 标题自适应填充 */
    }
    
    .view-options {
      font-size: 24rpx;
      color: #666;
    }
  }
  
  .card-body {
    .data-value {
      font-size: 44rpx;
      font-weight: 700;
      color: #2c3e50;
      display: block;
      margin-bottom: 8rpx;
    }
    
    .timestamp {
      font-size: 24rpx;
      color: #7f8c8d;
    }
  }
}

/* 状态栏 - 顶部边框分割内容 */
.status-bar {
  margin-top: 30rpx;
  padding: 20rpx;
  text-align: center;
  font-size: 24rpx;
  color: #666;
  border-top: 1rpx solid #eee; /* 分割线 */
}

/* 加载层 - 固定定位覆盖全屏 */
.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.8); /* 半透明背景 */
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 999; /* 确保在最上层 */
  
  .loading-spinner {
    text-align: center;
    
    /* 旋转动画 */
    .uni-icons[type="spinner-cycle"] {
      animation: spin 1s linear infinite;
    }
    
    .loading-text {
      display: block;
      margin-top: 16rpx;
      font-size: 32rpx;
      color: #555;
    }
  }
}

/* 旋转动画定义 */
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
</style>